/**
 * 中间件模式, 一个简易的带上下文的中间件
 */
const Emitter = require('events')

const context = {
  name: 'mengqi',
  year: 18 
}

class Application extends Emitter {
  constructor() {
    super()
    this.middleware = []
    this.ctx = Object.create(context)
  }

  use(fn) {
    if (typeof fn !== 'function') throw new TypeError('middleware must be a function!')
    this.middleware.push(fn)
    return this
  }

  exec() {
    const middleware = this.compose(this.middleware)
    middleware()
  }

  compose(middleware) {
    if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
    for (const fn of middleware) {
      if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
    }
    
    return () => {
      let index = -1
      return dispatch(0)
      
      function dispatch(i) {
        if (i <= index) return Promise.reject(new Error('next() called multiple times'))
        index = i
        let fn = middleware[i]
        if (i === middleware.length) fn = next
        if (!fn) return Promise.resolve()
        try {
          return Promise.resolve(fn(context, function next () {
            return dispatch(i + 1)
          }))
        } catch (err) {
            return Promise.reject(err)
        }
      } 
    }

  }

}

function checkNameMiddleware(ctx, next) {
  if(ctx.name) {
    console.log(ctx.name)  
    return next()
  }
}

function checkYearMiddleware(ctx, next) {
  if(ctx.year) {
    console.log(ctx.year)
    return next()
  }
}

function checkGenderMiddleware(ctx, enxt) {
  if(ctx.gender) {
    console.log(ctx.gender)
    return next()
  } 
}

const app = new Application()

// 中间件1 
app.use(checkNameMiddleware)
// 中间件2
app.use(checkYearMiddleware)
// 中间件3
app.use(checkGenderMiddleware)

app.exec()
